package com.tsd.core.utils;

import com.alibaba.fastjson.JSON;
import com.tsd.core.constants.Constants;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.Map.Entry;

/**
 * http网络处理工具类
 */
public class HttpUtil {

    /**
     * 获取request的header，经过URLDecoder.decode
     * @param request
     * @param key
     * @return
     */
    public static String getHeader(HttpServletRequest request,String key){
        String value = request.getHeader(key);
        return decodeHeaderValue(value);
    }

    /**
     * 获取账套号，先从Header获取，没有则从parameter获取，然后再进行URLDecod，以支持中文
     * @param request
     * @return
     */
    public static String getAccountSet(HttpServletRequest request){
        String account_set_sid = request.getHeader(Constants.HEADER_NAME_ACCOUNT_SET_SID);
        if (HlpUtils.isEmpty(account_set_sid)) {
            account_set_sid = request.getParameter(Constants.HEADER_NAME_ACCOUNT_SET_SID);
        }
        account_set_sid = decodeHeaderValue(account_set_sid);
        return account_set_sid;
    }
    /**
     * 对header value进行decode
     * @param value
     * @return
     */
    public static String decodeHeaderValue(String value){
        if (!HlpUtils.isEmpty(value) && value.contains("%")) {
            try {
                value = java.net.URLDecoder.decode(value, "UTF-8");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return value;
    }
    /**
     * http Get方法访问数据，默认返回的数据为UTF-8编码
     *
     * @param url url地址
     * @return
     * @throws IOException
     */

    public static String getUrl(HttpClient httpClient, String url)
            throws IOException {
        return getUrl(httpClient, url, "UTF-8");
    }

    /**
     * http Get方法访问数据，以指定的字符编码返回字符串
     *
     * @param httpClient
     * @param url
     * @param encoding
     * @return
     * @throws IOException
     */
    public static String getUrl(HttpClient httpClient, String url,
                                String encoding) throws IOException {
        HttpGet request = new HttpGet(url);
        if (httpClient == null) {
            httpClient = new DefaultHttpClient();
        }
        HttpResponse response = httpClient.execute(request);
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toString(response.getEntity(), encoding);
        } else {
            return "";
        }
    }

    /**
     * post提交数据（UTF-8编码）
     *
     * @param url    提交地址
     * @param params 参数
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String postUrl(HttpServletRequest servletRequest, String url,
                                 Map<String, String> params) throws
            IOException {
        return postUrl(servletRequest, url, params, "UTF-8");
    }


    /**
     * post提交数据
     *
     * @param url      提交地址
     * @param params   参数
     * @param encoding 参数编码
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String postUrl(HttpServletRequest servletRequest, String url,
                                 Map<String, String> params, String encoding)
            throws ClientProtocolException, IOException {

        List<NameValuePair> param = new ArrayList<>();
        if (params != null) {
            // 添加参数
            Iterator<Entry<String, String>> iterator = params.entrySet()
                    .iterator();
            while (iterator.hasNext()) {
                Entry<String, String> entry = iterator.next();

                param.add(new BasicNameValuePair(entry.getKey(), entry
                        .getValue()));
            }
        }

        HttpPost request = new HttpPost(url);
        if (servletRequest != null) {
            String sid = (String) servletRequest.getSession().getAttribute(
                    "JSESSIONID");
            request.setHeader("Cookie", "JSESSIONID=" + sid);
        }


        HttpEntity entity = new UrlEncodedFormEntity(param, encoding);
        request.setEntity(entity);

        DefaultHttpClient client = new DefaultHttpClient();

        client.getParams().setParameter(
                CoreConnectionPNames.CONNECTION_TIMEOUT, 20000); // 设置请求超时时间
        client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 60000); // 读取超时

        HttpResponse response = client.execute(request);

        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            List<Cookie> cookies = client.getCookieStore().getCookies();
            for (int i = 0; i < cookies.size(); i++) {
                if ("JSESSIONID".equals(cookies.get(i).getName())) {
                    servletRequest.getSession().setAttribute("JSESSIONID", cookies.get(i).getValue());
                    break;
                }
            }
            return EntityUtils.toString(response.getEntity());
        } else {
            return null;
        }
    }

    /**
     * 以raw json的方式post数据到指定的url
     *
     * @param urlString
     * @param data
     * @return
     */
    public static String postData(String urlString, String data) {
        OutputStream outStream = null;
        InputStream in = null;
        StringBuffer buf = new StringBuffer();
        HttpURLConnection conn = null;
        try {
            // 创建一个 URL 对象
            URL url = new URL(urlString);

            // 创建一个 URL 连接，如果有代理的话可以指定一个代理。
            // URLConnection connection = url.openConnection(Proxy_yours);
            // 对于 HTTP 连接可以直接转换成 HttpURLConnection，这样就可以使用一些 HTTP 连接特定的方法，如
            // setRequestMethod() 等:
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setInstanceFollowRedirects(true);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestMethod("POST");
            // 在开始和服务器连接之前，可能需要设置一些网络参数
            conn.setConnectTimeout(10000);

            // conn.addRequestProperty("User-Agent","J2me/MIDP2.0");

            // 连接到服务器
            conn.connect();

            // 与服务器交互:
            outStream = conn.getOutputStream();
            outStream.write(data.getBytes());
            /*
             * ObjectOutputStream objOutput = new ObjectOutputStream(outStream);
             * objOutput.writeObject(data);
             */
            outStream.flush();
            in = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = reader.readLine()) != null) {
                buf.append(line);
            }
            reader.close();
        } catch (Exception e) {
            // 网络读写操作往往会产生一些异常，所以在具体编写网络应用时
            // 最好捕捉每一个具体以采取相应措施
        } finally {
            FileUtil.safeCloseInputStrem(in);
            FileUtil.safeCloseOutputStrem(outStream);
            if (conn != null) {
                conn.disconnect();
            }
        }
        return buf.toString();
    }

    /**
     * 以raw json的方式post数据到指定的url
     *
     * @param urlString
     * @param data
     * @return
     */
    public static String postJsonData(String urlString, Map<String, Object> headers, Map<String, Object> data) throws IOException {
        OutputStream outStream = null;
        InputStream in = null;
        StringBuffer buf = new StringBuffer();
        HttpURLConnection conn = null;
        try {
            // 创建一个 URL 对象
            URL url = new URL(urlString);

            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setInstanceFollowRedirects(true);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestMethod("POST");
            // 在开始和服务器连接之前，可能需要设置一些网络参数
            conn.setConnectTimeout(10000);
            if (headers != null && headers.size() > 0) {
                Set<String> keys = headers.keySet();
                for (String key : keys) {
                    conn.setRequestProperty(key, HlpUtils.getString(headers, key));
                }
            }
            conn.connect();
            outStream = conn.getOutputStream();
            outStream.write(JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8));
            outStream.flush();
            in = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = reader.readLine()) != null) {
                buf.append(line);
            }
            reader.close();
        } finally {
            FileUtil.safeCloseInputStrem(in);
            FileUtil.safeCloseOutputStrem(outStream);
            if (conn != null) {
                conn.disconnect();
            }
        }
        return buf.toString();
    }

    /**
     * post提交数据(form方式)
     *
     * @param url      提交地址
     * @param params   参数
     * @param encoding 参数编码
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String postUrlSimple(String url, Map<String, String> params, String encoding) throws Exception {
        List<NameValuePair> param = new ArrayList<NameValuePair>(); // 参数
        // param.add(new BasicNameValuePair("par", "request-post"));
        // //这个参数我不知道是不是非要加这个
        if (params != null) {
            // 添加参数
            for (Entry<String, String> entry : params.entrySet()) {
                param.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        HttpPost request = new HttpPost(url);

        HttpEntity entity = new UrlEncodedFormEntity(param, encoding);
        request.setEntity(entity);

        DefaultHttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(
                CoreConnectionPNames.CONNECTION_TIMEOUT, 20000); // 设置请求超时时间
        client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 60000); // 读取超时

        HttpResponse response = client.execute(request);

        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toString(response.getEntity());
        } else {
            throw new Exception(response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase());
        }
    }

    /**
     * 获取http response的头内容
     *
     * @param http
     * @return
     * @throws UnsupportedEncodingException
     */
    private static Map<String, String> getHttpResponseHeader(
            HttpURLConnection http) throws UnsupportedEncodingException {
        Map<String, String> header = new LinkedHashMap<String, String>();
        for (int i = 0; ; i++) {
            String mine = http.getHeaderField(i);
            if (mine == null)
                break;
            header.put(http.getHeaderFieldKey(i), mine);
        }
        return header;
    }

    /**
     * 以Row json模式发送数据到指定url
     *
     * @param urlString
     * @param data
     * @param charCode
     * @return
     */
    public static byte[] postUrlRawJSON(String urlString, String data, String charCode) {
        OutputStream outStream = null;
        InputStream in = null;
        byte[] bytes = null;
        HttpURLConnection conn = null;
        try {
            // 创建一个 URL 对象
            URL url = new URL(urlString);

            // 创建一个 URL 连接，如果有代理的话可以指定一个代理。
            // URLConnection connection = url.openConnection(Proxy_yours);
            // 对于 HTTP 连接可以直接转换成 HttpURLConnection，这样就可以使用一些 HTTP 连接特定的方法，如
            // setRequestMethod() 等:
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setInstanceFollowRedirects(true);
            conn.setRequestProperty("Content-Type", "text/plain");
            conn.setRequestMethod("POST");
            // 在开始和服务器连接之前，可能需要设置一些网络参数
            conn.setConnectTimeout(10000);

            // conn.addRequestProperty("User-Agent","J2me/MIDP2.0");

            // 连接到服务器
            conn.connect();

            // 与服务器交互:
            outStream = conn.getOutputStream();
            outStream.write(data.getBytes(charCode == null ? "UTF-8" : charCode));
            outStream.flush();
            Map<String, String> header = getHttpResponseHeader(conn);
            String leng = header.get("Content-Length");
            int length = 0;
            if (!HlpUtils.isEmpty(leng)) {
                length = Integer.parseInt(leng);
                bytes = new byte[length];
            }
            in = conn.getInputStream();
            byte[] buf = new byte[10240];
            int c = 0;
            int totalCount = 0;
            while ((c = in.read(buf)) != -1) {
                System.arraycopy(buf, 0, bytes, totalCount + 0, c);
                totalCount += c;
            }
        } catch (Exception e) {
            // 网络读写操作往往会产生一些异常，所以在具体编写网络应用时
            // 最好捕捉每一个具体以采取相应措施
            e.printStackTrace();
        } finally {
            FileUtil.safeCloseInputStrem(in);
            FileUtil.safeCloseOutputStrem(outStream);
            if (conn != null) {
                conn.disconnect();
            }
        }
        return bytes;
    }

    /**
     * 获取客户IP地址
     *
     * @param request
     * @return
     */
    public static String getClientIP(HttpServletRequest request) {
        String forwardedIp = request.getHeader("X-Forwarded-For");
        String ip;
        if (!HlpUtils.isEmpty(forwardedIp)) {
            String[] forwardedIpSp = forwardedIp.split(",");
            ip = forwardedIpSp[0];
        } else {
            ip = request.getHeader("X-Real-IP");
        }
        if (HlpUtils.isEmpty(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
